package org.hcf.data;

import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.hcf.common.UserSigInfo;
import org.hcf.data.cache.CacheConfig;
import org.hcf.data.cache.Caches;
import org.hcf.data.entity.*;
import org.hcf.data.redis.RedisCacheKey;
import org.hcf.data.service.*;
import org.redisson.api.RKeys;
import org.redisson.api.RMap;
import org.redisson.api.RedissonClient;
import org.tio.utils.cache.ICache;

import java.util.*;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Collectors;


/**
 * 常用redis封装
 */
@Slf4j
public class RedisUtils {
    /** 通过腾讯云群ID获取群数据。若缓存中不存在，将在数据库中获取，并缓存期间所有映射关系 */
    public static ChatGroup getGroupByAccount(String groupAccount) {
        return getGroupByAccount(groupAccount, true);
    }

    /**
     * 通过腾讯云群ID获取群数据。若缓存中不存在，将在数据库中获取。
     * @param groupAccount 腾讯云群ID
     * @param isCache 是否缓存数据库查询期间产生的所有映射关系
     * @return 群数据
     */
    public static ChatGroup getGroupByAccount(String groupAccount, boolean isCache) {
        return getGroupByAccount(groupAccount, true, isCache);
    }

    /**
     * 通过腾讯云群ID获取群数据
     * @param groupAccount 腾讯云群ID
     * @param isCheckDB 是否在数据库中查询缓存中没有的数据
     * @param isCache 是否缓存数据库查询期间产生的所有映射关系
     * @return 群数据
     */
    public static ChatGroup getGroupByAccount(String groupAccount, boolean isCheckDB, boolean isCache) {
        Long groupId = getGroupIDByAccount(groupAccount, isCheckDB, isCache);
        if (groupId != null) return getGroup(groupId, isCheckDB, isCache);
        return null;
    }

    /**
     * 通过腾讯云群ID获取群ID。若缓存中不存在，将在数据库中获取，并缓存期间所有映射关系
     * @param groupAccount 腾讯云群ID
     * @return 群ID
     */
    public static Long getGroupIDByAccount(String groupAccount) {
        return getGroupIDByAccount(groupAccount, true);
    }

    /**
     * 通过腾讯云群ID获取群ID。若缓存中不存在，将在数据库中获取
     * @param groupAccount 腾讯云群ID
     * @param isCache 是否缓存数据库查询期间产生的所有映射关系
     * @return 群ID
     */
    public static Long getGroupIDByAccount(String groupAccount, boolean isCache) {
        return getGroupIDByAccount(groupAccount, true, isCache);
    }

    /**
     * 通过腾讯云群ID获取群ID
     * @param groupAccount 腾讯云群ID
     * @param isCheckDB 是否在数据库中查询缓存中没有的数据
     * @param isCache 是否缓存数据库查询期间产生的所有映射关系
     * @return 群ID
     */
    public static Long getGroupIDByAccount(String groupAccount, boolean isCheckDB, boolean isCache) {
        Long groupId = Caches.getCache(CacheConfig.GROUP_ACCOUNT).get(groupAccount, Long.class);
        if (groupId == null && isCheckDB) {
            groupId = SqlHelper.getService(IChatGroupService.class).getByAccount(groupAccount);
            if (groupId != null && isCache) Caches.getCache(CacheConfig.GROUP_ACCOUNT).put(groupAccount, groupId);
        }
        return groupId;
    }

    public static RedissonClient client;
    public static RKeys keys;

    /** 获取缓存中用户数据 */
    public static ICache getUserMap() {
        return Caches.getCache(CacheConfig.USER_ID);
    }

    /** 获取缓存中用户电话与用户ID的映射 */
    public static ICache getPhoneMap() {
        return Caches.getCache(CacheConfig.USER_PHONE);
    }

    /** 获取缓存中用户账号与用户ID的映射 */
    public static ICache getAccountMap() {
        return Caches.getCache(CacheConfig.USER_ACCOUNT);
    }

    public static RMap<String, Long> getTokenClientMap() {
        return client.getMap(RedisCacheKey.PLUGIN_TOKEN_CLIENT_MAP);
    }

    public static RMap<String, String> getMatrixMap() {
        return client.getMap(RedisCacheKey.PLUGIN_MATRIX_MAP);
    }

    public static RMap<String, Long> getMatrixUserMap() {
        return client.getMap(RedisCacheKey.PLUGIN_MATRIX_ID_USER_MAP);
    }

    public static RMap<Long, String> getUserMatrixMap() {
        return client.getMap(RedisCacheKey.PLUGIN_USER_MATRIX_ID_MAP);
    }

    public static RMap<Integer, byte[]> getRoomInfoMap() {
        return client.getMap(RedisCacheKey.GAME_ROOM_MAP);
    }

    /** 从缓存中获取群数据 */
    public static ICache getGroupMap() {
        return Caches.getCache(CacheConfig.GROUP_ID);
    }

    public static AtomicLong msgId;

    public static AtomicLong getMsgId() {
        if (msgId == null) msgId = new AtomicLong(SqlHelper.getService(IChatMsgService.class).getMaxMsgId());
        return msgId;
    }

    public static RMap<Long, ChatMsg> getMessageMap() {
        return client.getMap(RedisCacheKey.MESSAGE_MAP);
    }

    public static void putMessage(ChatMsg msg) {
        if (msg == null) return;
        if (msg.getMsgId() <= 0) msg.setMsgId(getMsgId().incrementAndGet());
        getMessageMap().put(msg.getMsgId(), msg);
    }


    public static void saveMessage() {
        RMap<Long, ChatMsg> map = getMessageMap();
        Map<Long, ChatMsg> ms = new HashMap<>(map);
        IChatMsgService service = SqlHelper.getService(IChatMsgService.class);
        if (ms.size() > 1000) {
            List<ChatMsg> list = new ArrayList<>();
            for (Map.Entry<Long, ChatMsg> entry : ms.entrySet()) {
                if (entry.getValue() != null) {
                    list.add(entry.getValue());
                    if (list.size() % 1000 == 0) {
                        service.saveBatch(list);
                        list.clear();
                    }
                }
                map.remove(entry.getKey());
            }
            if (list.size() > 0) service.saveBatch(list);
        } else {
            service.saveBatch(ms.values());
            for (Long id : ms.keySet()) map.remove(id);
        }

    }

    public static ChatMsg getMessage(long messageId) {
        ChatMsg msg = getMessageMap().get(messageId);
        if (msg == null) msg = SqlHelper.getService(IChatMsgService.class).getMessage(messageId);
        return msg;
    }

    public static Set<ChatMsg> getMessage(List<Long> ids) {
        Set<ChatMsg> ms = new HashSet<>();
        if (ids == null) return ms;
        Set<Long> notIds = new HashSet<>();
        RMap<Long, ChatMsg> map = getMessageMap();
        for (Long id : ids) {
            ChatMsg msg = map.get(id);
            if (msg != null) ms.add(msg);
            else notIds.add(id);
        }
        if (notIds.size() > 0) {
            ms.addAll(SqlHelper.getService(IChatMsgService.class).getMessages(new ArrayList<>(notIds)));
        }
        return ms;
    }

    /** 获取用户ID与群成员ID映射 */
    public static ICache getUID2GMIDs() {
        return Caches.getCache(CacheConfig.USER_GROUP_MEMBER);
    }

    /**
     * 获取用户所在的所有群中群成员ID。若缓存中不存在，将在数据库中获取。并缓存数据库查询期间产生的所有映射关系。
     * @param userId 用户ID
     * @return 群成员ID集合
     */
    public static Set<Long> getUID2GMIDs(long userId) {
        return getUID2GMIDs(userId, true);
    }

    /**
     * 获取用户所在的所有群中群成员ID。若缓存中不存在，将在数据库中获取。
     * @param userId 用户ID
     * @param isCache 是否缓存数据库查询期间产生的所有映射关系
     * @return 群成员ID集合
     */
    public static Set<Long> getUID2GMIDs(long userId, boolean isCache) {
        return getUID2GMIDs(userId, true, isCache);
    }

    /**
     * 获取用户所在的所有群中群成员ID。
     * @param userId 用户ID
     * @param isCheckDB 是否在数据库中查询缓存中没有的数据
     * @param isCache 是否缓存数据库查询期间产生的所有映射关系
     * @return
     */
    public static HashSet<Long> getUID2GMIDs(long userId, boolean isCheckDB, boolean isCache) {
        HashSet<Long> infos = getUID2GMIDs().get(String.valueOf(userId), HashSet.class);
        if ((infos == null || infos.size() == 0) && isCheckDB) {
            HashSet<Long> temp = new HashSet<>(SqlHelper.getService(IChatGroupInfoService.class).getGroupInfo(userId).stream().map(ChatGroupInfo::getInfoId).collect(Collectors.toList()));
            if (isCache) getUID2GMIDs().put(String.valueOf(userId), temp);
            return temp;
        }
        return infos;
    }

    /**
     * 添加用户ID与群成员ID的映射到缓存中
     * @param userId 用户ID
     * @param groupMemberId 群成员ID
     */
    public static void initUID2GMID(long userId, long groupMemberId) {
        Set<Long> gms = getUID2GMIDs(userId);
        if (gms == null) getUID2GMIDs().put(String.valueOf(userId), new HashSet<>(Arrays.asList(groupMemberId)));
        else if (gms.add(groupMemberId)) getUID2GMIDs().put(String.valueOf(userId), (HashSet<Long>) gms);
    }

    /** 从缓存中删除用户ID与群成员ID的映射 */
    public static void removeUID2GMID(long userId, long groupMemberId) {
        HashSet<Long> gms = getUID2GMIDs(userId, false, false);
        if (gms != null && gms.remove(groupMemberId)) getUID2GMIDs().put(String.valueOf(userId), gms);
    }

    /** 从缓存中获取群ID与成员ID映射 */
    public static ICache getGID2GMIDs() {
        return Caches.getCache(CacheConfig.GROUP_GROUP_MEMBER);
    }

//    public static Set<Long> getGID2GMIDs(long groupId) {
//        return getGID2GMIDs().get(String.valueOf(groupId), HashSet.class);
////        return client.getSet(RedisCacheKey.GROUP_GROUP_INFO_DATA + groupId);
//    }


    /** 通过群ID */
    public static Set<Long> getGID2GMIDs(long groupId) {
        return getGID2GMIDs(groupId, true);
    }

    public static Set<Long> getGID2GMIDs(long groupId, boolean isCache) {
        return getGID2GMIDs(groupId, true, isCache);
    }

    public static Set<Long> getGID2GMIDs(long groupId, boolean isCheckDB, boolean isCache) {
        Set<Long> gmids = getGID2GMIDs().get(String.valueOf(groupId), HashSet.class);
        if ((gmids == null || gmids.size() == 0) && isCheckDB) {
            HashSet<Long> temp = new HashSet<>(SqlHelper.getService(IChatGroupInfoService.class).getGroupInfoByGroup(groupId).stream().map(ChatGroupInfo::getInfoId).collect(Collectors.toList()));
            if (isCache) {
                if (gmids != null) gmids.addAll(temp);
                else gmids = new HashSet<>(temp);
                getGID2GMIDs().put(String.valueOf(groupId), (HashSet<Long>) gmids);
            }
            return temp;
        }
        return gmids;
    }

    public static Map<Long, Set<Long>> getGroupInfoIds(boolean isCheckDB, boolean isCache, Long... groupIds) {
        Map<Long, Set<Long>> map = new HashMap<>();
        HashSet<Long> vgids = new HashSet<>();
        for (Long groupId : groupIds) {
            Set<Long> ids = getGID2GMIDs(groupId, isCheckDB, isCache);
            if (ids == null || ids.size() == 0) vgids.add(groupId);
            else map.put(groupId, ids);
        }
        if (vgids.size() > 0 && isCheckDB) {
            List<ChatGroupInfo> infos = SqlHelper.getService(IChatGroupInfoService.class).getGroupInfoByGroups(new ArrayList<>(vgids));
            if (infos.size() > 0) {
                Map<Long, Set<Long>> temp = new HashMap<>();
                for (ChatGroupInfo info : infos) {
                    Set<Long> ids = temp.get(info.getGroupId());
                    if (ids == null) {
                        ids = new HashSet<>();
                        temp.put(info.getGroupId(), ids);
                    }
                    ids.add(info.getInfoId());
                }
                if (isCache) {
                    for (Map.Entry<Long, Set<Long>> entry : temp.entrySet()) {
                        Set<Long> gmids = getGID2GMIDs(entry.getKey());
                        if (gmids != null) gmids.addAll(entry.getValue());
                        else getGID2GMIDs().put(entry.getKey().toString(), new HashSet<>(entry.getValue()));
                    }
                }
                map.putAll(temp);
            }
        }
        return map;
    }

    /** 获取群成员映射缓存 */
    public static ICache getGroupMembers() {
        return Caches.getCache(CacheConfig.GROUP_MEMBER);
//        return  client.getMap(RedisCacheKey.GROUP_INFO_DATA);
    }

    /**
     * 根据群成员ID获取群成员数据。若缓存中不存在，将在数据库中获取。并缓存数据库查询期间所有映射关系。
     * @param ids 群成员ID集合
     * @return 群成员数据
     */
    public static Set<ChatGroupInfo> getGroupMembers(Long... ids) {
        return getGroupMembers(true, ids);
    }

    /**
     * 根据群成员ID获取群成员数据。若缓存中不存在，将在数据库中获取。
     * @param isCache 是否缓存数据库查询期间所有映射关系
     * @param ids 群成员ID集合
     * @return 群成员数据
     */
    public static Set<ChatGroupInfo> getGroupMembers(boolean isCache, Long... ids) {
        return getGroupMembers(true, isCache, ids);
    }

    /**
     * 根据群成员ID获取群成员数据。
     * @param isCheckDB 是否在数据库中查询缓存中没有的数据
     * @param isCache 是否缓存数据库查询期间所有映射关系
     * @param ids 群成员ID集合
     * @return 群成员数据
     */
    public static Set<ChatGroupInfo> getGroupMembers(boolean isCheckDB, boolean isCache, Long... ids) {
        List<Long> is = new ArrayList<>();
        ICache cache = getGroupMembers();
        Set<ChatGroupInfo> infos = new HashSet<>();
        for (Long id : ids) {
            ChatGroupInfo info = cache.get(id.toString(), ChatGroupInfo.class);
            if (info != null) infos.add(info);
            else is.add(id);
        }
        if (is.size() > 0 && isCheckDB) {
            List<ChatGroupInfo> temp = SqlHelper.getService(IChatGroupInfoService.class).getGroupInfos(ids);
            if (temp.size() > 0) {
                infos.addAll(temp);
                if (isCache) {
                    for (ChatGroupInfo info : infos) {
                        putMember(info);
                    }
                }
            }
        }
        return infos;
    }

    public static ChatGroupInfo getGroupMember(long userId, long groupId) {
        Set<ChatGroupInfo> members = getGroupMemberFromUser(userId, false, false);
        ChatGroupInfo info = null;
        if (members != null && members.size() > 0)
            for (ChatGroupInfo member : members) if (member.getGroupId() == groupId) return member;
        return SqlHelper.getService(IChatGroupInfoService.class).getGroupInfo(userId, groupId);
//        if (ids == null || ids.size() == 0) {
//
//        }
//        return getGroupInfos(false, false, ids.toArray(new Long[0])).stream().filter(v -> v.getGroupId() == groupId).findFirst().get();
    }

    public static Set<ChatGroupInfo> getGroupMemberFromUser(long userId) {
        return getGroupMemberFromUser(userId, true);
    }

    public static Set<ChatGroupInfo> getGroupMemberFromUser(long userId, boolean isCache) {
        return getGroupMemberFromUser(userId, true, isCache);
    }

    public static Set<ChatGroupInfo> getGroupMemberFromUser(long userId, boolean isCheckDB, boolean isCache) {
        Set<Long> ids = getUID2GMIDs(userId, isCheckDB, isCache);
        if (ids != null && ids.size() > 0) return getGroupMembers(isCheckDB, isCache, ids.toArray(new Long[]{}));
        return null;
    }

    /** 获取群中所有关系 */
    public static Set<ChatGroupInfo> getGroupGroupInfos(long groupId) {
        return getGroupGroupInfos(groupId, true);
    }

    /** 获取群中所有关系 */
    public static Set<ChatGroupInfo> getGroupGroupInfos(long groupId, boolean isCache) {
        return getGroupGroupInfos(groupId, true, isCache);
    }

    /** 获取群中所有关系 */
    public static Set<ChatGroupInfo> getGroupGroupInfos(long groupId, boolean isCheckDB, boolean isCache) {
        Set<Long> ids = getGID2GMIDs(groupId, isCheckDB, isCache);
        return getGroupMembers(isCheckDB, isCache, ids.toArray(new Long[]{}));
    }

    public static Map<Long, Map<Long, ChatGroupInfo>> getGroupGroupInfos(boolean isCheckDB, boolean isCache, Long... groupIds) {
        Map<Long, Set<Long>> idmap = getGroupInfoIds(isCheckDB, isCache, groupIds);
        Map<Long, Map<Long, ChatGroupInfo>> map = new HashMap<>();
        for (Map.Entry<Long, Set<Long>> entry : idmap.entrySet()) {
            map.put(entry.getKey(), getGroupMembers(isCheckDB, isCache, entry.getValue().toArray(new Long[0])).stream().collect(Collectors.toMap(ChatGroupInfo::getUserId, v -> v, (o1, o2) -> o1)));
        }
        return map;
    }

    public static Set<ChatGroup> getGroups(Long... ids) {
        return getGroups(true, ids);
    }

    public static Set<ChatGroup> getGroups(boolean isCache, Long... ids) {
        return getGroups(true, isCache, ids);
    }

    public static Set<ChatGroup> getGroups(boolean isCheckDB, boolean isCache, Long... ids) {
        ICache cache = getGroupMap();
        List<Long> is = new ArrayList<>();
        Set<ChatGroup> groups = new HashSet<>();
        for (Long id : ids) {
            ChatGroup group = cache.get(id.toString(), ChatGroup.class);
            if (group != null) groups.add(group);
            else is.add(id);
        }
        if (is.size() > 0 && isCheckDB) {
            List<ChatGroup> list = SqlHelper.getService(IChatGroupService.class).getGroups(is);
            if (list.size() > 0) {
                groups.addAll(list);
                if (isCache) {
                    for (ChatGroup group : list) putGroup(group);
                }
            }
        }
        return groups;
    }

    public static RMap<Long, ChatFriend> getFriendMap(long userId) {
        return client.getMap(RedisCacheKey.FRIEND_INFO_DATA + userId);
    }

    public static Map<Long, ChatFriend> getFriends(long userId) {
        return getFriends(userId, true);
    }

    public static Map<Long, ChatFriend> getFriends(long userId, boolean isCache) {
        return getFriends(userId, true, isCache);
    }

    public static Map<Long, ChatFriend> getFriends(long userId, boolean isCheckDB, boolean isCache) {
        RMap<Long, ChatFriend> map = getFriendMap(userId);
        if (map.size() == 0 && isCheckDB) {
            List<ChatFriend> temp = SqlHelper.getService(IChatFriendService.class).getFriends(userId);
            if (temp.size() > 0) {
                if (isCache)
                    map.putAll(temp.stream().collect(Collectors.toMap(ChatFriend::getToId, v -> v, (o1, o2) -> o1)));
                else return temp.stream().collect(Collectors.toMap(ChatFriend::getToId, v -> v, (o1, o2) -> o1));
            }
        }
        return new HashMap<>(map);
    }

//    public static RMap<Long, ChatApply> getApplyMap() {
//        return client.getMap(RedisCacheKey.APPLY_MAP);
//    }
//
//    public static void putApply(ChatApply apply) {
//        getApplyMap().put(apply.getApplyId(), apply);
//    }

//    public static Set<ChatApply> getApply(boolean isCheckDB, boolean isCache, Long... ids) {
//        RMap<Long, ChatApply> map = getApplyMap();
//        Set<Long> is = new HashSet<>();
//        Set<ChatApply> infos = new HashSet<>();
//        for (Long id : ids) {
//            ChatApply info = map.get(id);
//            if (info != null) infos.add(info);
//            else is.add(id);
//        }
//        if (is.size() > 0 && isCheckDB) {
//            List<ChatApply> list = SqlHelper.getService(IChatApplyService.class).listByIds(is);
//            if (list.size() > 0) {
//                infos.addAll(list);
//                if (isCache) map.putAll(list.stream().collect(Collectors.toMap(ChatApply::getApplyId, v -> v, (o1, o2) -> o1)));
//            }
//        }
//        return infos;
//    }

//    public static RSet<Long> getUserApplyData(long userId) {
//        return client.getSet(RedisCacheKey.USER_APPLY_DATA + userId);
//    }
//
//    public static RSet<Long> getGroupApplyData(long groupId) {
//        return client.getSet(RedisCacheKey.GROUP_APPLY_DATA + groupId);
//    }

//    public static Set<Long> getUserApplyIds(long userId, boolean isCheckDB, boolean isCache) {
//        RSet<Long> ids = getUserApplyData(userId);
//        if (ids.size() == 0 && isCheckDB) {
//            List<ChatApply> list = SqlHelper.getService(IChatApplyService.class).getApplyAll(userId);
//            if (list.size() > 0) {
//                if (isCache) ids.addAll(list.stream().map(ChatApply::getApplyId).collect(Collectors.toList()));
//                return list.stream().map(ChatApply::getApplyId).collect(Collectors.toSet());
//            }
//        }
//        return new HashSet<>(ids);
//    }
//
//    public static Set<ChatApply> getUserApply(Long... userIds) {
//        return getUserApply(true, userIds);
//    }

//    public static Set<ChatApply> getUserApply(boolean isCache, Long... userIds) {
//        return getUserApply(true, isCache, userIds);
//    }
//
//    public static Set<ChatApply> getUserApply(boolean isCheckDB, boolean isCache, Long... userIds) {
//        Set<Long> ids = getUserApplyIds(isCheckDB, isCache, userIds);
//        Set<ChatApply> infos = new HashSet<>();
//        if (ids.size() > 0) {
//            infos.addAll(getApply(isCheckDB, isCache, ids.toArray(new Long[0])));
//        }
//        return infos;
//    }

//    public static Set<Long> getUserApplyIds(boolean isCheckDB, boolean isCache, Long... userIds) {
//        Set<Long> ids = new HashSet<>();
//        Set<Long> us = new HashSet<>();
//        for (Long userId : userIds) {
//            RSet<Long> applyIds = getUserApplyData(userId);
//            if (applyIds.size() > 0) ids.addAll(applyIds);
//            else us.add(userId);
//        }
//        if (us.size() > 0 && isCheckDB) {
//            List<ChatApply> allApplyList = SqlHelper.getService(IChatApplyService.class).getApplyAll(new ArrayList<>(us));
//            if (allApplyList.size() > 0) {
//                ids.addAll(allApplyList.stream().map(ChatApply::getApplyId).collect(Collectors.toList()));
//                if (isCache) {
//                    Map<Long, Set<Long>> map = new HashMap<>();
//                    for (ChatApply apply : allApplyList) {
//                        Set<Long> data = map.get(apply.getFromId());
//                        if (data == null) {
//                            data = new HashSet<>();
//                            map.put(apply.getFromId(), data);
//                        }
//                        data.add(apply.getApplyId());
//                        if (apply.getFromId() == apply.getToId()) continue;
//                        data = map.get(apply.getToId());
//                        if (data == null) {
//                            data = new HashSet<>();
//                            map.put(apply.getFromId(), data);
//                        }
//                        data.add(apply.getApplyId());
//                    }
//                    for (Long userId : us) {
//                        Set<Long> applyIds = map.get(userId);
//                        if (applyIds != null && applyIds.size() > 0) getUserApplyData(userId).addAll(applyIds);
//                    }
//                }
//            }
//        }
//        return ids;
//    }
//
//    public static Set<Long> getGroupApplyIds(long groupId, boolean isCheckDB, boolean isCache) {
//        RSet<Long> ids = getGroupApplyData(groupId);
//        if (ids.size() == 0 && isCheckDB) {
//            List<ChatApply> list = SqlHelper.getService(IChatApplyService.class).getApplyByGroup(groupId);
//            if (list.size() > 0) {
//                if (isCache) ids.addAll(list.stream().map(ChatApply::getApplyId).collect(Collectors.toList()));
//                return list.stream().map(ChatApply::getApplyId).collect(Collectors.toSet());
//            }
//        }
//        return ids;
//    }

    public static void putFriendInfo(ChatFriend friend) {
        getFriendMap(friend.getFromId()).put(friend.getToId(), friend);
    }

//    public static void putApply(ChatApply apply) {
//        getApply(apply.getFromId()).add(apply);
//        getApply(apply.getToId()).add(apply);
//    }

    public static ChatUser getUser(long userId) {
        return getUser(userId, false);
    }

    public static ChatUser getUser(long userId, boolean isCache) {
        return getUser(userId, true, isCache);
    }

    public static ChatUser getUser(long userId, boolean isCheckDB, boolean isCache) {
        ChatUser user = getUserMap().get(String.valueOf(userId), ChatUser.class);
        if (user == null && isCheckDB) {
            user = SqlHelper.getService(IChatUserService.class).getById(userId);
            if (isCache) putUser(user);
        }
        return user;
    }

    public static List<ChatUser> getUsers(Long... userIds) {
        return getUsers(true, false, userIds);
    }

    public static List<ChatUser> getUsers(boolean isCache, Long... userIds) {
        return getUsers(true, isCache, userIds);
    }

    public static List<ChatUser> getUsers(boolean isCheckDB, boolean isCache, Long... userIds) {
        List<ChatUser> users = new ArrayList<>();
        ICache map = getUserMap();
        List<Long> us = new ArrayList<>();
        for (Long userId : userIds) {
            ChatUser user = map.get(String.valueOf(userId), ChatUser.class);
            if (user != null) users.add(user);
            else us.add(userId);
        }
        if (us.size() > 0 && isCheckDB) {
            List<ChatUser> temps = SqlHelper.getService(IChatUserService.class).getUserByIds(us.toArray(new Long[0]));
            if (temps.size() > 0) {
                users.addAll(temps);
                if (isCache) {
                    for (ChatUser temp : temps) putUser(temp);
//                    map.putAll(temps.stream().collect(Collectors.toMap(ChatUser::getUserId, v -> v, (o1, o2) -> o1)));
                }
            }
        }
        return users;
    }

    public static ChatUser getUser(String phone) {
        return getUser(phone, true);
    }

    public static ChatUser getUser(String phone, boolean isCache) {
        return getUser(phone, true, isCache);
    }

    public static ChatUser getUser(String phone, boolean isCheckDB, boolean isCache) {
        Long userId = getPhoneMap().get(phone, Long.class);
        if (userId == null && isCheckDB) {
            ChatUser user = SqlHelper.getService(IChatUserService.class).getUserByPhone(phone);
            if (user != null && isCache) {
                putUser(user);
            }
            return user;
        }
        return userId != null ? RedisUtils.getUser(userId, isCheckDB, isCache) : null;
    }

    public static ChatUser getAccount(String account) {
        return getAccount(account, true);
    }

    public static ChatUser getAccount(String account, boolean isCache) {
        return getAccount(account, true, isCache);
    }

    public static ChatUser getAccount(String account, boolean isCheckDB, boolean isCache) {
        Long userId = getAccountMap().get(account, Long.class);
        if (userId == null && isCheckDB) {
            ChatUser user = SqlHelper.getService(IChatUserService.class).getUserByAccount(account);
            if (user != null && isCache) {
                putUser(user);
            }
            return user;
        }
        return userId != null ? RedisUtils.getUser(userId, isCheckDB, isCache) : null;

    }


    public static void putUser(ChatUser user) {
        getUserMap().put(user.getUserId().toString(), user);
        if (StrUtil.isNotBlank(user.getPhone())) getPhoneMap().put(user.getPhone(), user.getUserId());
        if (StrUtil.isNotBlank(user.getAccount())) getAccountMap().put(user.getAccount(), user.getUserId());
    }

    public static UserSigInfo getUserSig(long userId) {
        byte[] bs = Caches.getCache(CacheConfig.USER_SIG).get(String.valueOf(userId), byte[].class);
        if (bs == null) return null;
        return UserSigInfo.from(bs);
    }

    public static void put(UserSigInfo info) {
        Caches.getCache(CacheConfig.USER_SIG).put(String.valueOf(info.getUserId()), info.toBytes());
    }

    public static ChatGroup getGroup(long groupId) {
        return getGroup(groupId, true);
    }

    public static ChatGroup getGroup(long groupId, boolean isCache) {
        return getGroup(groupId, true, isCache);
    }

    public static ChatGroup getGroup(long groupId, boolean isCheckDB, boolean isCache) {
        ChatGroup group = getGroupMap().get(String.valueOf(groupId), ChatGroup.class);
        if (group == null && isCheckDB) {
            group = SqlHelper.getService(IChatGroupService.class).getById(groupId);
            if (group != null && isCache) putGroup(group);
        }
        return group;
    }

    public static ICache getGA2UID() {
        return Caches.getCache(CacheConfig.PLUGIN_GA_UID);
    }

    public static HashSet<Long> getGA2UID(String groupAccount) {
        return getGA2UID().get(groupAccount, HashSet.class);
    }

    public static void initPluginUser(long userId) {
        Set<ChatGroupInfo> gms = getGroupMemberFromUser(userId);
        if (gms == null || gms.size() == 0) return;
        Set<Long> gids = gms.stream().filter(v -> v.isKeepGroup()).map(v -> v.getGroupId()).collect(Collectors.toSet());
        if (gids == null || gms.size() == 0) return;
        getGroups(gids.toArray(new Long[0]));
    }

    public static void initGA2UID(long userId) {
        Set<ChatGroupInfo> members = RedisUtils.getGroupMemberFromUser(userId);
        if (members == null || members.size() == 0) return;
        Set<Long> gids = members.stream().filter(v -> v.isKeepGroup()).map(v -> v.getGroupId()).collect(Collectors.toSet());
        if (gids == null || gids.size() == 0) return;
        Set<ChatGroup> gs = RedisUtils.getGroups(gids.toArray(new Long[0]));
        if (gs != null && gs.size() == 0) return;
        gs = gs.stream().filter(v -> !v.isDispose()).collect(Collectors.toSet());
        for (ChatGroup group : gs) initGA2UID(group.getGroupAccount(), userId);
    }

    public static void initGA2UID(String groupAccount, Long... userIds) {
        HashSet<Long> uids = getGA2UID().get(groupAccount, HashSet.class);
        if (uids == null)
            getGA2UID().put(groupAccount, new HashSet<>(Arrays.asList(userIds)));
        else if (uids.addAll(Arrays.asList(userIds))) getGA2UID().put(groupAccount, uids);
    }

    public static void removeGA2UID(long userId) {
        Set<ChatGroupInfo> members = RedisUtils.getGroupMemberFromUser(userId, false, false);
        if (members == null || members.size() == 0) return;
        Set<Long> gids = members.stream().filter(v -> v.isKeepGroup()).map(v -> v.getGroupId()).collect(Collectors.toSet());
        if (gids == null || gids.size() == 0) return;
        Set<ChatGroup> gs = RedisUtils.getGroups(false, gids.toArray(new Long[0]));
        if (gs != null && gs.size() == 0) return;
        for (ChatGroup group : gs) removeGA2UID(group.getGroupAccount(), userId);

    }

    public static void removeGA2UID(String groupAccount, Long... userIds) {
        HashSet<Long> uids = getGID2GMIDs().get(groupAccount, HashSet.class);
        if (uids != null && uids.removeAll(Arrays.asList(userIds))) getGID2GMIDs().put(groupAccount, uids);
    }


    public static void putGroup(ChatGroup group) {
        getGroupMap().put(group.getGroupId().toString(), group);
        Caches.getCache(CacheConfig.GROUP_ACCOUNT).put(group.getGroupAccount(), group.getGroupId());
    }

    public static void putMember(ChatGroupInfo memberInfo) {
        getGroupMembers().put(memberInfo.getInfoId().toString(), memberInfo);
    }
}
